package com.witframework.web.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;

import com.witframework.core.ApplicationProperties;

/**
 * this class loads the frameworks, javascript files and css files from the jar
 * file changes to the javascript or css files can only be done by repacking the
 * jar
 *
 */
public final class SourceLoader extends GenericServlet {
	private static Log log = LogFactory.getLog(SourceLoader.class);
	private static final String cacheRegionName = "default";
	private String prefix = null;	

	/**
	 * this is the base where we can find the source wich sould be loaded
	 */
	public final static String BASE = "/com/witframework/webroot/framework/webresource";

	/**
	 * write the content from the jarfile to the client stream use
	 * bufferedwriter to handel newline the filename is found in the requestURI
	 * the contextpath is excluded and replaced with the base package name
	 */
	@Override
	public void service(ServletRequest req0, ServletResponse resp0)
			throws ServletException, IOException {
		boolean cache=Boolean.parseBoolean(ApplicationProperties.getProperty("resource.cache", "false"));	
		HttpServletResponse resp = (HttpServletResponse) resp0;
		HttpServletRequest req = (HttpServletRequest) req0;
		String res = req.getRequestURI();	
		String sub = res.substring(req.getContextPath().length());
		if(sub.indexOf(prefix,prefix.length())>0)
			sub=sub.substring(sub.indexOf(prefix,prefix.length()));
		String name="";
		if (prefix != null && sub.startsWith(prefix)) {
			sub = sub.substring(prefix.length());
			name = SourceLoader.BASE + sub;
		}else if(sub.startsWith("/this")){
			sub = sub.substring("/this".length());
			name=""+sub;
		}
		OutputStream stream= resp.getOutputStream();
		if(StringUtils.isNotEmpty(name)){
			if(cache&&isCanCacheObject(name)){
				long s=System.currentTimeMillis();
				byte[] resouceContent=getCacheResource(name);
				System.out.println(System.currentTimeMillis()-s);
				if(resouceContent!=null){
					stream.write(resouceContent);
					return;
				}
			}
			{//如果不缓存或是尚未缓存
				InputStream in ;//= this.getClass().getResourceAsStream(name);
				URL resourceURL=this.getClass().getResource(name);
				if(resourceURL==null){
					System.out.println("resource not found (" + name + ")");
				}else{		
					if(resourceURL.getProtocol().equals("file"))
						in=new java.io.FileInputStream(java.net.URLDecoder.decode(resourceURL.getPath(),"utf-8").replace(resourceURL.getProtocol()+":",""));
					else
						in = this.getClass().getResourceAsStream(name);
					if (in == null) {
						throw new ServletException("resource not found (" + name + ")");
					}					
					byte[] buffer = new byte[10240];
					int len = -1;
					while ((len = in.read(buffer)) != -1) {					
						stream.write(buffer, 0, len);		
						if(cache&&isCanCacheObject(name)){
							cacheResource(name,buffer,len);
						}
					}
				}
			}
		}
	}

	@Override
	public void init() throws ServletException {
		prefix = trim2Null(getInitParameter("prefix"));			
	}
	public static String trim2Null(String str) {
		if (str != null && str.trim().length() > 0) {
			return str;
		}
		return null;
	}
	private boolean isCanCacheObject(String name){
		return name.endsWith(".css")||name.endsWith(".js");
	}
	private JCS getCache(){
		JCS cache;
		try{
			return JCS.getInstance(cacheRegionName);			
        }catch (CacheException e){
            log.error( "Problem initializing cache for region name [" + cacheRegionName + "].", e );
        }
        return null;
	}
	private byte[] getCacheResource(String name){
		JCS cache=getCache();		
		return (byte[])cache.get(name);
	}
	private void cacheResource(String name,byte[] c,int length){
		JCS cache=getCache();			
		byte[] content=(byte[])cache.get(name);
		byte[] temp;
		if(content!=null){
			temp=new byte[content.length+length];
			System.arraycopy(content, 0, temp, 0, content.length);
			System.arraycopy(c, 0, temp, content.length,length);
		}else{
			temp=new byte[length];			
			System.arraycopy(c, 0, temp, 0,length);
		}		
		try {
			cache.remove(name);
			cache.put(name,temp);
		} catch (CacheException e) {			
			log.error( "Problem set cache for region name [" + cacheRegionName + "].", e );
		}		
	}
}
